from flask import Flask, request, send_file
from flask_restful import Resource, abort, Api, reqparse
from werkzeug.datastructures import FileStorage
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

from biz_inter import Biz

import os
import shutil
import logging
import pyotp

otp  = pyotp.parse_uri('otpauth://totp/cstool:otpuser?secret=L6N3YFXKMRSIQNWROTB5A5MZWGQLCDSA&issuer=cstool')

app = Flask(__name__)
api = Api(app)


limiter = Limiter(get_remote_address, app=app, default_limits=["10 per minute"])


source_dir = './source'
result_dir = './result'

class SalesDataIntegration(Resource):
    decorators = [limiter.limit("1 per second")]

    def get_upload_files(self, files):
        file_11 = None
        file_13 = None
        for f in files:
            logging.info(f"filename:{f.filename}")
            if f.filename.endswith('11.csv'):
                file_11 = f
                continue

            if f.filename.endswith('13.csv'):
                file_13 = f
        return file_11, file_13

    def prepare_args(self):
        parser = reqparse.RequestParser()
        parser.add_argument('week', type=int, location='form', required=True)
        parser.add_argument('year', type=int, location='form', required=True)
        parser.add_argument('vcode', type=str, location='form', required=True)
        parser.add_argument('files', type=FileStorage, location='files', action='append', required=True)
        args = parser.parse_args()

        if not otp.verify(args['vcode']):
            abort(401, message="vcode verify failed!")

        logging.info(f"input week: {args['week']}, year: {args['year']}")

        files = request.files.getlist('files')
        file_11, file_13 = self.get_upload_files(files)
        if file_11 is None:
            abort(400, message="Missing required upload file, name as *11.csv")
        if file_13 is None:
            abort(400, message="Missing required upload file, name as *13.csv")
        logging.info(f"files: {file_11}, {file_13}")
        return args['week'], args['year'], file_11, file_13

    def remove_up_tmp_files(self, f11, f13):
        try:
            os.remove(f11)
            os.remove(f13)
        except Exception as e:
            logging.error(f"remove source file failed: {e}")

    def post_result(self, year, week, file11, file13):
        url_pre = '/download/'
        f11= f'{source_dir}/{file11.filename}'
        f13= f'{source_dir}/{file13.filename}'
        file11.save(f11)
        file13.save(f13)

        ret = Biz.create(year, week, f11, f13, result_dir).run()
        self.remove_up_tmp_files(f11, f13)

        if not ret:
            return {'success': False}

        date_str = "%s%2d" % (str(year), week)
        return {'success': True,
                'data': {'week': week,
                         'year': year,
                         'files': {'local_region': {'url': '/download/',
                                                    'fname': f'result_local_region_week_{date_str}.csv'},
                                   'sales_country_ob': {'url': '/download/',
                                                        'fname': f'result_sales_country_week_ob_{date_str}.csv'},
                                   'sales_region_ob': {'url': '/download/',
                                                       'fname': f'result_sales_region_week_ob_{date_str}.csv'},
                                   'trade_line': {'url': '/download/',
                                                  'fname': f'result_trade_line_week_{date_str}.csv'},
                                   'sales_country_ib': {'url': '/download/',
                                                        'fname': f'result_sales_country_week_ib_{date_str}.csv'},
                                   'sales_region_ib': {'url': '/download/',
                                                       'fname': f'result_sales_region_week_ib_{date_str}.csv'}
                                   }
                         }
                }

    def post(self):
        week, year, file11, file13 = self.prepare_args()
        return self.post_result(year, week, file11, file13)
        

class SalesDataIntegrationTest(SalesDataIntegration):
    def post_result(self, week, year, file11, file13):
        return {'success': True,
                'data': {'week': week,
                         'year': year,
                         'upload_11': file11,
                         'upload_13': file13,
                         'files': {'local_region': {'url': 'www.baidu.com',
                                                    'fname': 'result_local_region_week_202410.csv'},
                                   'sales_country_ob': {'url': 'www.baidu.com',
                                                        'fname': 'result_sales_country_week_ob_202410.csv'},
                                   'sales_region_ob': {'url': 'www.baidu.com',
                                                       'fname': 'result_sales_region_week_ob_202410.csv'},
                                   'trade_line': {'url': 'www.baidu.com',
                                                  'fname': 'result_trade_line_week_202410.csv'},
                                   'sales_country_ib': {'url': 'www.baidu.com',
                                                        'fname': 'result_sales_country_week_ib_202410.csv'},
                                   'sales_region_ib': {'url': 'www.baidu.com',
                                                       'fname': 'result_sales_region_week_ib_202410.csv'}
                                   }
                         }
                }

    def post(self):
        week, year, file11, file13 = self.prepare_args()
        return self.post_result(week, year, file11.filename, file13.filename)


class DownloadFile(Resource):
    decorators = [limiter.limit("1 per second")]

    def get(self, filename):
        logging.info(f'download filename: {filename}')
        file_path = f'./result/{filename}'
        if (os.path.exists(file_path)):
            return send_file(file_path, as_attachment=True)
        else:
            abort(404, message=f"{filename} not exists")

class ClearResult(Resource):
    decorators = [limiter.limit("1 per second")]

    def post(self):
        shutil.rmtree(result_dir) 
        os.mkdir(result_dir)
        return {'success': True}


api.add_resource(SalesDataIntegration, '/')
api.add_resource(SalesDataIntegrationTest, '/test')
api.add_resource(DownloadFile, '/download/<filename>')
api.add_resource(ClearResult, '/clear')


if __name__ == '__main__':
    logging.basicConfig(level=logging.INFO)
    app.run(debug=True, port=8003)
